﻿using System;
using System.Collections;
using NCrontab;
using SQLPXBase;

namespace GianosNET.Common.Classes
{
    public abstract class ScheduledService:LoopingService
    {
        internal bool ImmediateExecute { get; set; }
        internal bool ImmediateExecuteAfterException { get; private set; }
        protected CrontabSchedule Schedule { get; private set; }

        public ScheduledService(bool enableAutoStart, ServerInfo info) : base(enableAutoStart, info)
        {
        }

        public ScheduledService(string svcName, string version, Hashtable config, ProxyManager<sqlStatus> statusProxyMgr, bool enableAutoStart, ServerInfo info) : base(svcName, version, config, statusProxyMgr, enableAutoStart, info)
        {
            lock (this)
            {
                LoadSchedule();
            }
        }

        private void LoadSchedule()
        {
            string crontabStr = config["crontab"] as string ?? "";
            if (string.IsNullOrEmpty(crontabStr))
                throw new Exception("Crontab string is empty");

            ValueOrError<CrontabSchedule> sched = CrontabSchedule.TryParse(crontabStr);
            if (sched.IsError)
                throw new Exception(string.Format("Crontab string is invalid: {0}", sched.Error.Message));

            Schedule = sched.Value;

            ImmediateExecute = ImmediateExecute || (config["executeImmediately"] as string ?? "").ToLower() == "true"; // Only loads from config if value is false.. if it has been already set as true (for example after an exception), it keeps that setting
            ImmediateExecuteAfterException = (config["executeImmediatelyAfterException"] as string ?? "").ToLower() == "true";
        }

        public override int LoopingPause
        {
            get
            {
                DateTime d1 = DateTime.Now;
                DateTime d2 = NextOccurence;
                TimeSpan ts = d2.ToUniversalTime().Subtract(d1.ToUniversalTime());
                return Convert.ToInt32(ts.TotalSeconds);
            }
            set { /* dummy */ }
        }

        public DateTime NextOccurence
        {
            get
            {
                int waitLock = 0;
                while (true)
                {
                    if (Schedule != null)
                        return Schedule.GetNextOccurrence(DateTime.Now);

                    if (waitLock > 30)
                        throw new Exception("Scheduler not initialized yet");

                    System.Threading.Thread.Sleep(100);
                    waitLock++;
                }
            }
        }
    }
}
